module.exports = {
    encode(value, deep = 10) {
        function formatValue(value) {
            if (typeof (value) == 'object') {
                if (value instanceof Date) {
                    return `5${value.toString()}`
                } else if (value instanceof Array) {
                    return `4${JSON.stringify(value)}`
                } else {
                    return `6${JSON.stringify(value)}`
                }
            } else if (typeof (value) == 'string') {
                return `1${value}`
            } else if (typeof (value) == 'number') {
                return `2${value}`
            } else if (typeof (value) == 'boolean') {
                return `3${value ? 1 : 0}`
            } else if (typeof (value) == 'function') {
                return `7${value.toString()}`
            }
            return `0${value.toString()}`
        }
        value = formatValue(value)
        value = value.split('')

        function minWidth(length) {
            let width = 0
            while (width * width < length) {
                width++
            }
            return width
        }
        let width = minWidth(value.length)

        function random2(n) {
            return parseInt(Math.random() * 1000 % n)
        }
        function random() {
            return parseInt(Math.random() * Math.pow(10, random2(6)))
        }
        let data = []
        for (let i = 0; i < width; i++) {
            let c = []
            for (let i1 = 0; i1 < width; i1++) {
                c.push(value[i * width + i1] == undefined ? random() : value[i * width + i1].charCodeAt(0))
            }
            data.push(c)
        }
        value = data

        let route = []
        function change1(value, index1, index2) {
            let t = JSON.parse(JSON.stringify(value[index1]))
            value[index1] = value[index2]
            value[index2] = t
            return value
        }
        function change2(value, index1, index2) {
            for (let i = 0; i < width; i++) {
                let t = value[i][index1]
                value[i][index1] = value[i][index2]
                value[i][index2] = t
            }
            return value
        }
        for (let i = 0; i < deep && width > 1; i++) {
            let op = random2(2)
            let index1 = random2(width)
            let index2
            while (1) {
                index2 = random2(width)
                if (index2 != index1) break
            }
            if (op == 1) {
                value = change1(value, index1, index2)
            } else {
                value = change2(value, index1, index2)
            }
            route.push({
                op, index1, index2
            })
        }

        let str = `${width.toString().length}${width}`

        for (let i = 0; i < width; i++) {
            for (let i1 = 0; i1 < width; i1++) {
                str += `${value[i][i1].toString().length}${value[i][i1]}`
            }
        }

        for (let i = 0; i < route.length; i++) {
            let indexes = [route[i].index1, route[i].index2]
            if (route[i].op) {
                indexes.sort()
            } else {
                indexes.sort((a, b) => { return b - a })
            }
            str += `${indexes[0].toString().length}${indexes[0]}`
            str += `${indexes[1].toString().length}${indexes[1]}`
        }

        str = str.split('')
        let ss = ''
        function getLetter(c) {
            c = parseInt(c)
            c += 33
            if (c >= 33 && c <= 47 && c != 46 && c != 34) {
                return {
                    status: 1,
                    results: String.fromCharCode(c)
                }
            }
            if (c >= 58 && c <= 122) {
                return {
                    status: 1,
                    results: String.fromCharCode(c)
                }
            }
            if (c > 122) {
                return {
                    status: 0
                }
            }
            if (c < 33) {
                return {
                    status: -1
                }
            }
            return {
                status: 0
            }
        }

        let nstr = []
        for (let i = 0; i < str.length; i++) {
            ss += str[i]
            let ssglre = getLetter(ss)
            if (ssglre.status == 1) {
                nstr.push(ssglre.results)
            }
            if (ssglre.status == 0) {
                nstr.push(ss)
                ss = ''
            }
            if (ssglre.status == -1) {
                continue
            }
        }

        let res = ''
        for (let i = 0; i < nstr.length; i++) {
            res += nstr[i]
        }

        res = res.split('')

        for (let i = 0; i < res.length; i++) {
            if (res[i] == '0') res[i] = '{'
            if (res[i] == '1') res[i] = '|'
            if (res[i] == '2') res[i] = '}'
            if (res[i] == '3') res[i] = '~'
        }

        let index3 = 0
        let index4 = 1
        while (index4 < res.length) {
            if (res[index3] == res[index4]) {
                index4++
            } else {
                if ((index4 - index3) > 2) {
                    res[index3] = `${res[index3]}.${index4 - index3}.`
                    for (let i = index3 + 1; i < index4; i++) {
                        res[i] = ''
                    }
                }
                index3 = index4
            }
        }

        let res2 = ''

        for (let i = 0; i < res.length; i++) {
            res2 += res[i]
        }

        return res2
    },
    decode(encodedString) {
        let data = encodedString.split('.')
        for (let i = 0; i < data.length; i++) {
            if (i % 2) {
                data[i] = parseInt(data[i])
            }
        }
        function stringExp(c, n) {
            let t = c
            for (let i = 1; i < n; i++) {
                t += c
            }
            return t
        }
        for (let i = 0; i < data.length; i++) {
            if (typeof (data[i]) == 'number') {
                data[i] = stringExp(data[i - 1].slice(-1), data[i])
            }
        }
        let data1 = ''
        for (let i = 0; i < data.length; i++) {
            data1 += data[i]
        }
        data = data1
        data = data.split('')
        function changeLetterToNum(cb) {
            let c = cb.charCodeAt(0)
            if (c >= 33 && c <= 47 && c != 46 && c != 34) {
                return (c - 33).toString()
            }
            if (c >= 58 && c <= 122) {
                return (c - 33).toString()
            }
            return cb.toString()
        }
        let data2 = ''
        for (let i = 0; i < data.length; i++) {
            if (data[i] == '{') data[i] = '0'
            if (data[i] == '|') data[i] = '1'
            if (data[i] == '}') data[i] = '2'
            if (data[i] == '~') data[i] = '3'

            data2 += changeLetterToNum(data[i])
        }
        data = data2

        return data
    },
}